#include "EffectSprite.h"

/*********************| shader file path |*********************/
static const char* 			shader_res[EffectSprite::EFF_CNT] = {
	"#ifdef GL_ES\n"
	"precision mediump float;\n"
	"#endif\n"
	"uniform sampler2D u_texture;\n"
	"varying vec2 v_texCoord;\n"
	"varying vec4 v_fragmentColor;\n"
	"void main(void)\n"
	"{\n"
		"vec4 col = v_fragmentColor * texture2D(u_texture, v_texCoord); \n"
		"float grey = dot(col.rgb, vec3(0.299, 0.587, 0.114));\n"
		"gl_FragColor = vec4(grey, grey, grey, col.a);\n"
	"}",
	"#ifdef GL_ES \n"
	"precision mediump float; \n"
	"#endif \n"
	"uniform sampler2D u_texture; \n"
	"uniform float light; \n"
	"varying vec2 v_texCoord; \n"
	"varying vec4 v_fragmentColor; \n"
	"void main(void) \n"
	"{ \n"
		"vec4 col = v_fragmentColor * texture2D(u_texture, v_texCoord); \n"
		"if ((light < 0.01) || (col.a < 0.03)) {\n"
			"gl_FragColor = col;\n"
		"} else {\n"
			"gl_FragColor = col + vec4(light, light, light, 0);\n"
		"}\n"
	"}\n"
};
static const char* proKey[] = {
        "EFF_GREY_SHADER",
        "EFF_LIGHT_SHADER"
};

/*********************| effect sprite effect |*********************/
EffectSprite* EffectSprite::create(const char *res, int effectType, float data)
{
	if (effectType < 0 || effectType > EffectSprite::EFF_CNT)
		return NULL;
	EffectSprite* pRet = new EffectSprite();
	if (pRet ) {
		pRet->_data = data;
		pRet->_effectType = effectType;
		if (pRet->initWithFile(res)) {
			pRet->autorelease();
			return pRet;
		} else {
			pRet->release();
			goto do_err;
		}
	}
do_err:
	delete pRet;
	pRet = NULL;
	return pRet;
}

bool EffectSprite::initWithTexture(CCTexture2D *pTexture, const CCRect& rect)
{
	do {
		CC_BREAK_IF(!CCSprite::initWithTexture(pTexture, rect));
		if (EFF_NONE == _effectType) {
			return true;
		}
		_shFuncPos = 0;
		CCGLProgram* program = NULL;
		program = CCShaderCache::sharedShaderCache()->programForKey(proKey[_effectType]);
		if (!program) {
			program = new CCGLProgram();
			program->initWithVertexShaderByteArray(ccPositionTextureColor_vert, shader_res[_effectType]);
			CCShaderCache::sharedShaderCache()->addProgram(program, proKey[_effectType]);
			program->addAttribute(kCCAttributeNamePosition, kCCVertexAttrib_Position);
			program->addAttribute(kCCAttributeNameColor, kCCVertexAttrib_Color);
			program->addAttribute(kCCAttributeNameTexCoord, kCCVertexAttrib_TexCoords);
			CHECK_GL_ERROR_DEBUG();
			program->link();
			CHECK_GL_ERROR_DEBUG();
			program->updateUniforms();
			CHECK_GL_ERROR_DEBUG();
		}

		this->setShaderProgram(program);

		switch (_effectType) {
		case EffectSprite::EFF_LIGHTER:
			_shFuncPos = glGetUniformLocation( getShaderProgram()->getProgram(), "light");
			program->setUniformLocationWith1f(_shFuncPos, _data);
			break;
		case EffectSprite::EFF_GREY:
			break;
		};
		CHECK_GL_ERROR_DEBUG();

		return true;
	}while(0);
	return false;
}

void EffectSprite::draw()
{
	CC_NODE_DRAW_SETUP();

	ccGLBlendFunc( m_sBlendFunc.src, m_sBlendFunc.dst );

	ccGLBindTexture2D( m_pobTexture->getName() );
	ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex );

	switch (_effectType) {
	case EffectSprite::EFF_LIGHTER:
		getShaderProgram()->setUniformLocationWith1f(_shFuncPos, _data);
		break;
	case EffectSprite::EFF_GREY:
		break;
	}

#define kQuadSize sizeof(m_sQuad.bl)
#ifdef EMSCRIPTEN
	long offset = 0;
	setGLBufferData(&m_sQuad, 4 * kQuadSize, 0);
#else
	long offset = (long)&m_sQuad;
#endif // EMSCRIPTEN
	// vertex
	int diff = offsetof( ccV3F_C4B_T2F, vertices);
	glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff));
	// texCoods
	diff = offsetof( ccV3F_C4B_T2F, texCoords);
	glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));
	// color
	diff = offsetof( ccV3F_C4B_T2F, colors);
	glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff));

	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	CHECK_GL_ERROR_DEBUG();
	CC_INCREMENT_GL_DRAWS(1);
}
